﻿using System;
using System.Collections.Generic;

using System.Globalization;
using System.IO;
#if !NETFX_CORE && !UNIVERSAL
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
#else
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using System.Reflection;

#endif

namespace Prometheus.UIUtility
{
    /// <summary>
    /// Visual helper
    /// </summary>
    public static class UIHelper
    {
        public static bool IsInDesignMode(UIElement uiElement)
        {


#if !NETFX_CORE && !UNIVERSAL
            return DesignerProperties.GetIsInDesignMode(uiElement);
#else
            return Windows.ApplicationModel.DesignMode.DesignModeEnabled;
#endif
            
        }

        /// <summary>
        /// Whether the element is parent of enother element
        /// </summary>
        public static bool IsImplicitParent(this FrameworkElement element, UIElement parent, bool includeTemplatedParent = true)
        {
            return IsImplicitParent(element, parent, false, includeTemplatedParent);
        }

        private static bool IsImplicitParent(this FrameworkElement element, UIElement parent, bool includeThis, bool includeTemplatedParent)
        {
            if (parent == null) throw new InvalidOperationException("Агрумент parent не может быть Null");

            if (includeThis && element == parent) return true;

            bool val = false;
            if (element.Parent != null) val = IsImplicitParent((FrameworkElement)element.Parent, parent, true, includeTemplatedParent);

            if (!val && includeTemplatedParent)
            {
                var visParent = VisualTreeHelper.GetParent(element);
                if (visParent != null)
                    val = IsImplicitParent((FrameworkElement)visParent, parent, true, true);
            }
            return val;
        }

        public static T FindAncestor<T>(this FrameworkElement element) where T : DependencyObject
        {
            return element.FindAncestorUpstairs<T>(false, true);
        }

        public static T FindAncestor<T>(this FrameworkElement element, bool useTemplatedParent) where T : class
        {
            return element.FindAncestorUpstairs<T>(false, useTemplatedParent);
        }

        private static T FindAncestorUpstairs<T>(this DependencyObject element, bool includeThis, bool useTemplatedParent) where T : class
        {
            if (element == null) return default(T);

            if (includeThis)
                if (element is T)
                    return element as T;

            if (element is FrameworkElement && ((FrameworkElement)element).Parent != null)
            {
                var searchIt = ((FrameworkElement)element).Parent.FindAncestorUpstairs<T>(true, useTemplatedParent);
                if (searchIt != null) return searchIt;
            }

            if (!useTemplatedParent) return null;

            var parent2 = VisualTreeHelper.GetParent(element);
            return parent2.FindAncestorUpstairs<T>(true, true);
        }

#if SILVERLIGHT

        #if !WINDOWS_PHONE
        static UIHelper()
        {
            try
            {
                if (Application.Current.Host.Source != null)
                {
                    HostAbsoluteUri = Application.Current.Host.Source.AbsoluteUri;
                    QueryString = new Dictionary<string, string>(5);
                    foreach (var str in System.Windows.Browser.HtmlPage.Document.QueryString)
                    {
                        QueryString.Add(new KeyValuePair<string, string>(str.Key.ToUpper(), str.Value.ToUpper()));
                    }
                    AbsoluteCurrentPageUri = System.Windows.Browser.HtmlPage.Document.DocumentUri.AbsoluteUri;
                }
            }
            catch (InvalidOperationException)
            {

            }

        }

        /// <summary>
        /// Current Web Page Absolute Address
        /// </summary>
        public static string GetCurrentWebPageAddress()
        {
            var pagePath = AbsoluteCurrentPageUri;
            var index = pagePath.IndexOf(@"?", StringComparison.Ordinal);
            if (index != -1)
            {
                pagePath = pagePath.Substring(0, index);
            }
            return pagePath;
        }


        /// <summary>
        /// URL папки этого приложения
        /// </summary>
        public static string GetCurrentWebHostAddress()
        {
            var hostPath = HostAbsoluteUri;
            var slashIndex = hostPath.LastIndexOf(@"/", StringComparison.Ordinal);
            if (slashIndex != -1)
            {
                hostPath = hostPath.Substring(0, slashIndex + 1);
            }
            return hostPath;
        }

        private static readonly string HostAbsoluteUri;
        private static readonly IDictionary<string, string> QueryString;
        private static readonly string AbsoluteCurrentPageUri;



        public static string GenerateWebLink(string keyName, string value)
        {
            return string.Format(@"{0}?{1}={2}", GetCurrentWebPageAddress(), keyName.ToUpper(), value.ToUpper());
        }


        /// <summary>
        /// Url of currentPage, where SliverLIght is Hosting
        /// </summary>
        public static IDictionary<string, string> GetCurrentWebPageParameters()
        {
            return QueryString;
        }
#endif
        public static ResourceDictionary LoadVisualResource()
        {
            return new ResourceDictionary { Source = new Uri(@"/jSLCore.Client.Presentation;component/DefaultSLVisualStyle.xaml", UriKind.RelativeOrAbsolute) };
        }

        public static FrameworkElement GetFocusedElement(this Control control)
        {
            return FocusManager.GetFocusedElement() as FrameworkElement;
        }

        #if !WINDOWS_PHONE
        public static void ReloadHtmlPage()
        {
            System.Windows.Browser.HtmlPage.Window.Navigate(new Uri(GetCurrentWebPageAddress()));
        }
#endif

        public static string GetDefaultElementPath(this FrameworkElement element)
        {
            if (element is HyperlinkButton) return "Content";
            return null;
        }



        private const string DirtyHack = "";
        public static Uri CompileResourceString(string relativeUri)
        {
            return new Uri(string.Format(@"/jSLCore.Client.Presentation{0};component/{1}", DirtyHack, relativeUri),
                           UriKind.RelativeOrAbsolute);
        }

        public static bool ShowUIError(UIElement element, string errorText)
        {
            return false;//The code exists in ValidationBinding class for SilverLight
        }
#endif

#if !SILVERLIGHT
        public static FrameworkElement GetFocusedElement(this FrameworkElement control)
        {
            return FocusManager.GetFocusedElement(
#if !NETFX_CORE && !UNIVERSAL
                control
#endif
) as FrameworkElement;
        }

        public static string GetDefaultElementPath(this FrameworkElement element)
        {
#if !NETFX_CORE && !UNIVERSAL
            if (element is Hyperlink) return "Text";
#endif
            return null;
        }

        public static IEnumerable<FrameworkElement> GetVisualAncestorsAndSelf(this FrameworkElement element)
        {
            var ret = new List<FrameworkElement>(5);

            while (element != null)
            {
                ret.Add(element);
#if !NETFX_CORE && !UNIVERSAL
                var parent = element.Parent as FrameworkElement;
                if (parent == null) parent = element.TemplatedParent as FrameworkElement;
#else
                var parent = VisualTreeHelper.GetParent(element);
#endif
                element = (FrameworkElement)parent;
            }

            return ret.ToArray();
        }
#if !NETFX_CORE && !UNIVERSAL
         public static ResourceDictionary LoadVisualResource()
        {
            return new ResourceDictionary { Source = new Uri(@"/jSLCore.Client.Presentation.Wpf;component/DefaultWPFVisualStyle.xaml", UriKind.RelativeOrAbsolute) };
        }

        public static void SetSource(this BitmapImage image,Stream stream)
        {

     

            image.StreamSource = stream;

        }
        public const string DirtyHack = ".Wpf";
        public static Uri CompileResourceString(string relativeUri)
        {
            return new Uri(string.Format(@"/jSLCore.Client.Presentation{0};component/{1}", DirtyHack, relativeUri),
                           UriKind.RelativeOrAbsolute);
        }

        public static bool ShowUIError(FrameworkElement element,string errorText)
        {
            var binding = new Binding
                              {
                                  RelativeSource = new RelativeSource() { Mode = RelativeSourceMode.Self }
                              };
            var hackRule = new HackRule(errorText);
            
            binding.ValidationRules.Add(hackRule);

            var expression = element.SetBinding(DependencyErrorObject.CustomErrorProperty, binding);

            if (!string.IsNullOrEmpty(errorText))
            {
                var template = (ControlTemplate) element.TryFindResource("errorTemplate");

                if(template!=null)
                    Validation.SetErrorTemplate(element,template);
                
                Validation.MarkInvalid(expression, new ValidationError(hackRule, binding));
            }
            else
            {
                Validation.ClearInvalid(expression);
            }

            return true;//we did it
        }
#endif
#endif
    }

#if !SILVERLIGHT && !NETFX_CORE && !UNIVERSAL
    
    public class DependencyErrorObject : DependencyObject
    {
        public static readonly DependencyProperty CustomErrorProperty = DependencyProperty.Register("CustomError",
                                                                                                    typeof (string),
                                                                                                    typeof (
                                                                                                        DependencyErrorObject
                                                                                                        ));
        public string CustomError
        {
            get { return (string) GetValue(CustomErrorProperty); }
            set
            {
                SetValue(CustomErrorProperty,value);
            }
        }
    }

    public class HackRule : ValidationRule
    {
        private string errorText;

        public HackRule(string errorText)
        {
            this.errorText = errorText;
        }


        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            return new ValidationResult(false, errorText);
        }
    }
#endif
}